#include "CacheBase.h"

//CacheBase(QString tableName,QString createTableCmd,QObject *parent)
//    :QObject(parent)
//    ,m_tableName(tableName)
//    ,m_createTableCmd(createTableCmd)
CacheBase::CacheBase(QObject *parent) : QObject(parent)
{
    m_dataBaseInterface = DataBaseInterface::instance();
}

int CacheBase::encrypt(char *plaintext, int plaintext_len, char *key,
            char *iv, char *ciphertext)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int ciphertext_len = 0;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new()))
    {
        return  plaintext_len;
    }
//        evpHandleErrors();

    /*
     * Initialise the encryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     */
    if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL,reinterpret_cast<unsigned char*>(key), reinterpret_cast<unsigned char*>(iv)))
    {
        EVP_CIPHER_CTX_free(ctx);
        return  plaintext_len;
    }
//        evpHandleErrors();

    /*
     * Provide the message to be encrypted, and obtain the encrypted output.
     * EVP_EncryptUpdate can be called multiple times if necessary
     */
    if(1 != EVP_EncryptUpdate(ctx, reinterpret_cast<unsigned char *>(ciphertext), &len, reinterpret_cast<unsigned char*>(plaintext), plaintext_len))
    {
        EVP_CIPHER_CTX_free(ctx);
        return  plaintext_len;
    }
//        evpHandleErrors();
    ciphertext_len = len;

    /*
     * Finalise the encryption. Further ciphertext bytes may be written at
     * this stage.
     */
    if(1 != EVP_EncryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(ciphertext + len), &len))
    {
        EVP_CIPHER_CTX_free(ctx);
        return  plaintext_len;
    }
//        evpHandleErrors();
    ciphertext_len += len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return ciphertext_len;
}

//void CacheBase::createTable()
//{
//    m_dataBaseInterface->createTable(m_tableName);
//}

//bool CacheBase::saveInfo(const QString &info)
//{
//    QList<QString> infoList;
//    infoList<<info;
//    return saveInfo(infoList);
//}

//bool CacheBase::saveInfo(const QList<QString> &info)
//{
//    //	检查输入参数
//    bool state = false;
//    if (info.size()<=0)
//    {
//        state = false;
//        return state;
//    }
//    QList<QString>  key;
//    key << s_infoKey << s_stateKey;
//    QList<QList<QVariant>> value;
//    foreach(const QString &tempInfo,info)
//    {
//        QList<QVariant> tempValue;
//        QString enInfoValue;
//        QString statusInfoValue;
//        QString enStatusInfoValue;
//        // 生成加密信息字符串
//        encryptSimple(tempInfo,enInfoValue);
//        //	生成加密状态信息
//        QJsonObject tempObj;
//        tempObj.insert(gs_createTimeStampKey,QDateTime::currentDateTime().toMSecsSinceEpoch()/1000);
//        tempObj.insert(s_uploadTimesKey,0);
//        statusInfoValue = QString(QJsonDocument(tempObj).toJson(QJsonDocument::JsonFormat::Compact));
//        encryptSimple(statusInfoValue, enStatusInfoValue);
//        tempValue << enInfoValue << enStatusInfoValue;
//        value << tempValue;
//    }
//    state = m_dataBaseInterface->writeRow(m_tableName, key, value);
//    return state;
//}

//bool CacheBase::getInfo(qlonglong &id, QString &info, QString &status)
//{
//    bool state = false;
//    QList<qlonglong> idList;
//    QList<QString> infoList;
//    QList<QString> statusList;
//    state = getInfo(idList, infoList, statusList,s_singleNum);
//    if(state == false)
//    {
//        return	state;
//    }
//    if(idList.size() == s_singleNum
//        &&infoList.size() == s_singleNum
//        &&statusList.size() == s_singleNum)
//    {
//        id = idList.first();
//        info = infoList.first();
//        status = statusList.first();
//    }

//}

//bool CacheBase::getInfo(QList<qlonglong> &id, QList<QString> &info, QList<QString> &status, int32_t num)
//{
//    bool state = false;
//    if(num <= 0)
//    {
//        return state;
//    }
//    QList<QString> keyList;
//    keyList << s_idKey << s_infoKey << s_stateKey;
//    QList<QList<QVariant>> retList = m_dataBaseInterface->readRow(m_tableName,keyList,num);
//    if(retList.size() <= 0)
//    {
//        return;
//    }
//    //
//    for(int32_t indexNum=0; indexNum < retList.size();indexNum++)
//    {
//        for(int32_t indexKey=0; indexKey < uploadInfoKey.size(); indexKey++)
//        {
//            if(keyList.at(indexKey) == s_idKey)
//            {
//                id << retList.at(indexNum).at(indexKey).toLongLong();
//            }
//            else if(keyList.at(indexKey) == s_infoKey)
//            {
//                QString tempStr;
//                decryptSimple(retList.at(indexNum).at(indexKey).toString(), tempStr);
//                info << tempStr;
//            }
//            else if(keyList.at(indexKey) == s_stateKey)
//            {
//                QString tempStr;
//                decryptSimple(retList.at(indexNum).at(indexKey).toString(), tempStr);
//                status << tempStr;
//            }
//        }
//    }
//}

//bool CacheBase::updateInfo(const QList<qlonglong> &id, const QList<QString> &info, const QList<QString> &status)
//{
//    bool state = false;
//    if(id.size() != info.size() || info.size() != status.size() || info.size()<=0)
//    {
//        return state;
//    }
//    QList<QString> constraintKey;
//    QList<QList<QVariant>> constraintValue;
//    QList<QString> key;
//    QList<QList<QVariant>> value;
//    constraintKey << s_idKey;
//    key << s_infoKey << s_stateKey;
//    for(qlonglong index=0;index < id.size();index++)
//    {
//        QList<QVariant> tempConstraintValue;
//        QList<QVariant> tempValue;
//        QString enInfo;
//        QString enStatus;
//        // 检查status信息
//        QJsonDocument tempStatusJsonDoc = QJsonDocument::fromJson(status.at(index).toUtf8());
//        if(!tempStatusJsonDoc.isObject())
//        {
//            continue;
//        }
//        QJsonObject tempStatusJsonObj = tempStatusJsonDoc.object();
//        if(!tempStatusJsonObj.contains(s_uploadTimesKey))
//        {
//            continue;
//        }
//        tempStatusJsonObj[s_uploadTimesKey] = tempStatusJsonObj[s_uploadTimesKey].toInt() + 1 ;
//        encryptSimple(info.at(index), enInfo);
//        encryptSimple(QJsonDocument(tempStatusJsonObj).toJson(QJsonDocument::JsonFormat::Compact), enStatus);
//        qlonglong tempId = id.at(index);
//        tempConstraintValue << QVariant(tempId);
//        tempValue << enInfo << enStatus;
//    }
//    state = m_dataBaseInterface->updateRow(m_tableName,constraintKey,constraintValue,key,value);
//    return state;

//}

//bool CacheBase::deleteInfo(const qlonglong &id)
//{
//    QList<qlonglong> idList;
//    idList << id;
//    return   deleteInfo(idList);
//}

//bool CacheBase::deleteInfo(const QList<qlonglong> &id)
//{
//    //	检查输入参数
//    bool state = false;
//    if (id.size()<=0)
//    {
//    state = false;
//    return state;
//    }
//    QList<QString>  key;
//    key << s_idKey;
//    QList<QList<QVariant>> value;
//    foreach(qlonglong tempInfo,id)
//    {
//    QList<QVariant> tempValue;
//    tempValue << QVariant(tempInfo);
//    value << tempValue;
//    }
//    state = m_dataBaseInterface->deleteRow(m_tableName, key, value);
//    return state;
//}

//bool CacheBase::checkRow(qlonglong cacheRows)
//{
//    bool state;
//    state = m_dataBaseInterface->deleteMaxRow(m_tableName,s_idKey,cacheRows);
//    return state;
//}

//bool CacheBase::checkTime(qlonglong storageDuration)
//{
//    QList<QString> key;
//    QList<QList<QVariant>> value;
//    QList<qlonglong> id;
//    QList<QString> status;
//    QList<QString> deleteKey;
//    QList<QList<QVariant>> deleteId;
//    qlonglong nowTime = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000;
//    key<<s_idKey<<s_stateKey;
//    deleteKey << s_idKey;
//    int32_t checkInfoNum = s_checkInfoNum;
//    value = m_dataBaseInterface->readRow(m_tableName,key,checkInfoNum);
//    for(int32_t indexNum = 0; indexNum < value.size(); indexNum++)
//    {
//        for(int32_t indexKey=0;indexKey < key.size(); indexKey++)
//        {
//            if(key.at(indexKey) == s_idKey)
//            {
//                id << value.at(indexNum).at(indexKey).toLongLong();
//            }
//            else if(key.at(indexKey) == s_stateKey)
//            {
//                QString tempStr;
//                decryptSimple(value.at(indexNum).at(indexKey).toString(),tempStr);
//                status << tempStr;
//            }
//        }
//    }
//    for(int32_t indexNum=0;indexNum < id.size(); indexNum++)
//    {
//        QList<QVariant> tempDeleteId;
//        QJsonDocument tempJsonDoc = QJsonDocument::fromJson(status.at(indexNum).toUtf8());
//        if(!tempJsonDoc.isObject())
//        {
//            tempDeleteId << indexNum;
//            continue;
//        }
//        QJsonObject tempJsonObj = tempJsonDoc.object();
//        if(!tempJsonObj.contains(gs_createTimeStampKey))
//        {
//            tempDeleteId << indexNum;
//            continue;
//        }
//        if(nowTime - tempJsonObj[gs_createTimeStampKey].toInt() > storageDuration)
//        {
//            tempDeleteId << indexNum;
//            continue;
//        }
//        if(tempDeleteId.size()>0)
//        {
//            deleteId << tempDeleteId;
//        }

//    }
//    m_dataBaseInterface->deleteRow(m_tableName,deleteKey,deleteId);

//}

//bool CacheBase::checkTimes(qlonglong uploadTimes)
//{
//    QList<QString> key;
//    QList<QList<QVariant>> value;
//    QList<qlonglong> id;
//    QList<QString> status;
//    QList<QString> deleteKey;
//    QList<QList<QVariant>> deleteId;
//    qlonglong nowTime = QDateTime::currentDateTime().toMSecsSinceEpoch()/1000;
//    key<<s_idKey<<s_stateKey;
//    deleteKey << s_idKey;
//    int32_t checkInfoNum = s_checkInfoNum;
//    value = m_dataBaseInterface->readRow(m_tableName,key,checkInfoNum);
//    for(int32_t indexNum = 0; indexNum < value.size(); indexNum++)
//    {
//        for(int32_t indexKey=0;indexKey < key.size(); indexKey++)
//        {
//            if(key.at(indexKey) == s_idKey)
//            {
//                id << value.at(indexNum).at(indexKey).toLongLong();
//            }
//            else if(key.at(indexKey) == s_stateKey)
//            {
//                QString tempStr;
//                decryptSimple(value.at(indexNum).at(indexKey).toString(),tempStr);
//                status << tempStr;
//            }
//        }
//    }
//    for(int32_t indexNum=0;indexNum < id.size(); indexNum++)
//    {
//        QList<QVariant> tempDeleteId;
//        QJsonDocument tempJsonDoc = QJsonDocument::fromJson(status.at(indexNum).toUtf8());
//        if(!tempJsonDoc.isObject())
//        {
//            tempDeleteId << indexNum;
//            continue;
//        }
//        QJsonObject tempJsonObj = tempJsonDoc.object();
//        if(!tempJsonObj.contains(s_uploadTimesKey))
//        {
//            tempDeleteId << indexNum;
//            continue;
//        }
//        if(tempJsonObj[gs_createTimeStampKey].toInt() > uploadTimes)
//        {
//            tempDeleteId << indexNum;
//            continue;
//        }
//        if(tempDeleteId.size()>0)
//        {
//            deleteId << tempDeleteId;
//        }

//    }
//    m_dataBaseInterface->deleteRow(m_tableName,deleteKey,deleteId);

//}


int CacheBase::decrypt(char *ciphertext, int ciphertext_len, char *key,
            char *iv, char *plaintext)
{
    EVP_CIPHER_CTX *ctx;

    int len;

    int plaintext_len = 0;

    /* Create and initialise the context */
    if(!(ctx = EVP_CIPHER_CTX_new()))
    {
        return  plaintext_len;
    }

//        evpHandleErrors();

    /*
     * Initialise the decryption operation. IMPORTANT - ensure you use a key
     * and IV size appropriate for your cipher
     * In this example we are using 256 bit AES (i.e. a 256 bit key). The
     * IV size for *most* modes is the same as the block size. For AES this
     * is 128 bits
     */
    if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, reinterpret_cast<unsigned char*>(key), reinterpret_cast<unsigned char*>(iv)))
    {
        EVP_CIPHER_CTX_free(ctx);
        return  plaintext_len;
    }
//        evpHandleErrors();

    /*
     * Provide the message to be decrypted, and obtain the plaintext output.
     * EVP_DecryptUpdate can be called multiple times if necessary.
     */
    if(1 != EVP_DecryptUpdate(ctx, reinterpret_cast<unsigned char *>(plaintext), &len, reinterpret_cast<unsigned char *>(ciphertext), ciphertext_len))
    {
        EVP_CIPHER_CTX_free(ctx);
        return  plaintext_len;
    }
//        evpHandleErrors();
    plaintext_len = len;

    /*
     * Finalise the decryption. Further plaintext bytes may be written at
     * this stage.
     */
    if(1 != EVP_DecryptFinal_ex(ctx, reinterpret_cast<unsigned char *>(plaintext + len), &len))
    {
        EVP_CIPHER_CTX_free(ctx);
        return  plaintext_len;
    }

//        evpHandleErrors();
    plaintext_len += len;

    /* Clean up */
    EVP_CIPHER_CTX_free(ctx);

    return plaintext_len;
}

void CacheBase::encryptSimple(const QString &text, QString &enText)
{
    QByteArray cacheText = text.toUtf8();
    const char *plainText = cacheText.data();
    QScopedArrayPointer<char> cipherText(new char[cacheText.size() + s_maxStrLen]);
    int cipherTextLen = 0;
    cipherTextLen = encrypt(const_cast<char *>(plainText), cacheText.size(), const_cast<char *>(s_key), const_cast<char *>(s_iv), cipherText.data());
    if (cipherTextLen <= 0)
    {
        return ;
    }
    cipherText[cipherTextLen] = '\0';
    enText = QByteArray(cipherText.data(),cipherTextLen).toBase64();
}

void CacheBase::decryptSimple(const QString &text, QString &deText)
{
    QByteArray cacheText = QByteArray::fromBase64(text.toUtf8());
    const char *cipherText = cacheText.data();
    QScopedArrayPointer<char> plainText(new char[cacheText.size() + s_maxStrLen]);
    int plainTextLen = 0;
    plainTextLen = decrypt(const_cast<char *>(cipherText), cacheText.size(), const_cast<char *>(s_key), const_cast<char *>(s_iv), plainText.data());
    if (plainTextLen <= 0)
    {
        return ;
    }
    plainText[plainTextLen] = '\0';
    deText = QByteArray(plainText.data(),plainTextLen);
}
